home *** CD-ROM | disk | FTP | other *** search
/ Aminet 21 / Aminet 21 (1997)(GTI - Schatztruhe)[!][Oct 1997].iso / Aminet / gfx / show / gs_src_gs.lha / gs5.03 / gdevxini.c < prev    next >
C/C++ Source or Header  |  1997-05-04  |  33KB  |  1,002 lines

  1. /* Copyright (C) 1989, 1995, 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevxini.c */
  20. /* X Windows driver initialization for Ghostscript library */
  21. #include "math_.h"
  22. #include "memory_.h"
  23. #include "x_.h"
  24. #include "gx.h"
  25. #include "gserrors.h"
  26. #include "gxdevice.h"
  27. #include "gdevx.h"
  28.  
  29. extern char *getenv(P1(const char *));
  30.  
  31. private XtResource resources[] = {
  32.  
  33. /* (String) casts are here to suppress warnings about discarding `const' */
  34. #define RINIT(a,b,t,s,o,it,n)\
  35.   {(String)(a), (String)(b), (String)t, sizeof(s),\
  36.    XtOffsetOf(gx_device_X, o), (String)it, (n)}
  37. #define rpix(a,b,o,n)\
  38.   RINIT(a,b,XtRPixel,Pixel,o,XtRString,(XtPointer)(n))
  39. #define rdim(a,b,o,n)\
  40.   RINIT(a,b,XtRDimension,Dimension,o,XtRImmediate,(XtPointer)(n))
  41. #define rstr(a,b,o,n)\
  42.   RINIT(a,b,XtRString,String,o,XtRString,(char*)(n))
  43. #define rint(a,b,o,n)\
  44.   RINIT(a,b,XtRInt,int,o,XtRImmediate,(XtPointer)(n))
  45. #define rbool(a,b,o,n)\
  46.   RINIT(a,b,XtRBoolean,Boolean,o,XtRImmediate,(XtPointer)(n))
  47. #define rfloat(a,b,o,n)\
  48.   RINIT(a,b,XtRFloat,float,o,XtRString,(XtPointer)(n))
  49.  
  50.   rpix(XtNbackground, XtCBackground, background, "XtDefaultBackground"),
  51.   rpix(XtNborderColor, XtCBorderColor, borderColor, "XtDefaultForeground"),
  52.   rdim(XtNborderWidth, XtCBorderWidth, borderWidth, 1),
  53.   rstr("dingbatFonts", "DingbatFonts", dingbatFonts,
  54.        "ZapfDingbats: -Adobe-ITC Zapf Dingbats-Medium-R-Normal--"),
  55.   rpix(XtNforeground, XtCForeground, foreground, "XtDefaultForeground"),
  56.   rstr(XtNgeometry, XtCGeometry, geometry, NULL),
  57.   rbool("logExternalFonts", "LogExternalFonts", logXFonts, False),
  58.   rint("maxGrayRamp", "MaxGrayRamp", maxGrayRamp, 128),
  59.   rint("maxRGBRamp", "MaxRGBRamp", maxRGBRamp, 5),
  60.   rstr("palette", "Palette", palette, "Color"),
  61.  
  62.     /*
  63.      * I had to compress the whitespace out of the default string to
  64.      * satisfy certain balky compilers.
  65.      */
  66.   rstr("regularFonts", "RegularFonts", regularFonts, "\
  67. AvantGarde-Book:-Adobe-ITC Avant Garde Gothic-Book-R-Normal--\n\
  68. AvantGarde-BookOblique:-Adobe-ITC Avant Garde Gothic-Book-O-Normal--\n\
  69. AvantGarde-Demi:-Adobe-ITC Avant Garde Gothic-Demi-R-Normal--\n\
  70. AvantGarde-DemiOblique:-Adobe-ITC Avant Garde Gothic-Demi-O-Normal--\n\
  71. Bookman-Demi:-Adobe-ITC Bookman-Demi-R-Normal--\n\
  72. Bookman-DemiItalic:-Adobe-ITC Bookman-Demi-I-Normal--\n\
  73. Bookman-Light:-Adobe-ITC Bookman-Light-R-Normal--\n\
  74. Bookman-LightItalic:-Adobe-ITC Bookman-Light-I-Normal--\n\
  75. Courier:-Adobe-Courier-Medium-R-Normal--\n\
  76. Courier-Bold:-Adobe-Courier-Bold-R-Normal--\n\
  77. Courier-BoldOblique:-Adobe-Courier-Bold-O-Normal--\n\
  78. Courier-Oblique:-Adobe-Courier-Medium-O-Normal--\n\
  79. Helvetica:-Adobe-Helvetica-Medium-R-Normal--\n\
  80. Helvetica-Bold:-Adobe-Helvetica-Bold-R-Normal--\n\
  81. Helvetica-BoldOblique:-Adobe-Helvetica-Bold-O-Normal--\n\
  82. Helvetica-Narrow:-Adobe-Helvetica-Medium-R-Narrow--\n\
  83. Helvetica-Narrow-Bold:-Adobe-Helvetica-Bold-R-Narrow--\n\
  84. Helvetica-Narrow-BoldOblique:-Adobe-Helvetica-Bold-O-Narrow--\n\
  85. Helvetica-Narrow-Oblique:-Adobe-Helvetica-Medium-O-Narrow--\n\
  86. Helvetica-Oblique:-Adobe-Helvetica-Medium-O-Normal--\n\
  87. NewCenturySchlbk-Bold:-Adobe-New Century Schoolbook-Bold-R-Normal--\n\
  88. NewCenturySchlbk-BoldItalic:-Adobe-New Century Schoolbook-Bold-I-Normal--\n\
  89. NewCenturySchlbk-Italic:-Adobe-New Century Schoolbook-Medium-I-Normal--\n\
  90. NewCenturySchlbk-Roman:-Adobe-New Century Schoolbook-Medium-R-Normal--\n\
  91. Palatino-Bold:-Adobe-Palatino-Bold-R-Normal--\n\
  92. Palatino-BoldItalic:-Adobe-Palatino-Bold-I-Normal--\n\
  93. Palatino-Italic:-Adobe-Palatino-Medium-I-Normal--\n\
  94. Palatino-Roman:-Adobe-Palatino-Medium-R-Normal--\n\
  95. Times-Bold:-Adobe-Times-Bold-R-Normal--\n\
  96. Times-BoldItalic:-Adobe-Times-Bold-I-Normal--\n\
  97. Times-Italic:-Adobe-Times-Medium-I-Normal--\n\
  98. Times-Roman:-Adobe-Times-Medium-R-Normal--\n\
  99. Utopia-Bold:-Adobe-Utopia-Bold-R-Normal--\n\
  100. Utopia-BoldItalic:-Adobe-Utopia-Bold-I-Normal--\n\
  101. Utopia-Italic:-Adobe-Utopia-Regular-I-Normal--\n\
  102. Utopia-Regular:-Adobe-Utopia-Regular-R-Normal--\n\
  103. ZapfChancery-MediumItalic:-Adobe-ITC Zapf Chancery-Medium-I-Normal--"),
  104.  
  105.   rstr("symbolFonts", "SymbolFonts", symbolFonts,
  106.        "Symbol: -Adobe-Symbol-Medium-R-Normal--"),
  107.  
  108.   rbool("useBackingPixmap", "UseBackingPixmap", useBackingPixmap, True),
  109.   rbool("useExternalFonts", "UseExternalFonts", useXFonts, True),
  110.   rbool("useFontExtensions", "UseFontExtensions", useFontExtensions, True),
  111.   rbool("useScalableFonts", "UseScalableFonts", useScalableFonts, True),
  112.   rbool("useXPutImage", "UseXPutImage", useXPutImage, True),
  113.   rbool("useXSetTile", "UseXSetTile", useXSetTile, True),
  114.   rfloat("xResolution", "Resolution", xResolution, "0.0"),
  115.   rfloat("yResolution", "Resolution", yResolution, "0.0"),
  116.  
  117. #undef RINIT
  118. #undef rpix
  119. #undef rdim
  120. #undef rstr
  121. #undef rint
  122. #undef rbool
  123. #undef rfloat
  124. };
  125.  
  126. private String
  127. fallback_resources[] = {
  128.     (String)"Ghostscript*Background: white",
  129.     (String)"Ghostscript*Foreground: black",
  130.     NULL
  131. };
  132.  
  133. /* Define constants for orientation from ghostview */
  134. /* Number represents clockwise rotation of the paper in degrees */
  135. typedef enum {
  136.   Portrait = 0,        /* Normal portrait orientation */
  137.   Landscape = 90,    /* Normal landscape orientation */
  138.   Upsidedown = 180,    /* Don't think this will be used much */
  139.   Seascape = 270    /* Landscape rotated the wrong way */
  140. } orientation;
  141.  
  142. /* Forward references */
  143. private int gdev_x_setup_colors(P1(gx_device_X *));
  144. private void gdev_x_setup_fontmap(P1(gx_device_X *));
  145.  
  146. /* Catch the alloc error when there is not enough resources for the
  147.  * backing pixmap.  Automatically shut off backing pixmap and let the
  148.  * user know when this happens.
  149.  */
  150. private Boolean alloc_error;
  151. private XErrorHandler orighandler;
  152. private XErrorHandler oldhandler;
  153.  
  154. private int
  155. x_catch_alloc(Display *dpy, XErrorEvent *err)
  156. {
  157.     if (err->error_code == BadAlloc)
  158.     alloc_error = True;
  159.     if (alloc_error)
  160.     return 0;
  161.     return oldhandler(dpy, err);
  162. }
  163.  
  164. int
  165. x_catch_free_colors(Display *dpy, XErrorEvent *err)
  166. {
  167.     if (err->request_code == X_FreeColors) return 0;
  168.     return orighandler(dpy, err);
  169. }
  170.  
  171. /* Open the X device */
  172. int
  173. gdev_x_open(register gx_device_X *xdev)
  174. {
  175.     XSizeHints sizehints;
  176.     char *window_id;
  177.     XEvent event;
  178.     XVisualInfo xvinfo;
  179.     int nitems;
  180.     XtAppContext app_con;
  181.     Widget toplevel;
  182.     Display *dpy;
  183.     XColor xc;
  184.     int zero = 0;
  185.     int xid_height, xid_width;
  186.     int code;
  187.  
  188. #ifdef DEBUG
  189. # ifdef have_Xdebug
  190.     if (gs_debug['X']) {
  191.     extern int _Xdebug;
  192.  
  193.     _Xdebug = 1;
  194.     }
  195. # endif
  196. #endif
  197.     if (!(xdev->dpy = XOpenDisplay((char *)NULL))) {
  198.     char *dispname = getenv("DISPLAY");
  199.  
  200.     eprintf1("Cannot open X display `%s'.\n",
  201.          (dispname == NULL ? "(null)" : dispname));
  202.     return_error(gs_error_ioerror);
  203.     }
  204.     xdev->dest = 0;
  205.     if ((window_id = getenv("GHOSTVIEW"))) {
  206.     if (!(xdev->ghostview = sscanf(window_id, "%ld %ld",
  207.                        &(xdev->win), &(xdev->dest)))) {
  208.         eprintf("Cannot get Window ID from ghostview.\n");
  209.         return_error(gs_error_ioerror);
  210.     }
  211.     }
  212.     if (xdev->pwin != (Window)None) {/* pick up the destination window parameters if specified */
  213.     XWindowAttributes attrib;
  214.  
  215.     xdev->win = xdev->pwin;
  216.     if (XGetWindowAttributes(xdev->dpy, xdev->win, &attrib)) {
  217.         xdev->scr = attrib.screen;
  218.         xvinfo.visual = attrib.visual;
  219.         xdev->cmap = attrib.colormap;
  220.         xid_width = attrib.width;
  221.         xid_height = attrib.height;
  222.     } else {
  223.         /* No idea why we can't get the attributes, but */
  224.         /* we shouldn't let it lead to a failure below. */
  225.         xid_width = xid_height = 0;
  226.     }
  227.     }
  228.     else if (xdev->ghostview) {
  229.     XWindowAttributes attrib;
  230.     Atom type;
  231.     int format;
  232.     unsigned long nitems, bytes_after;
  233.     char *buf;
  234.     Atom ghostview_atom = XInternAtom(xdev->dpy, "GHOSTVIEW", False);
  235.  
  236.     if (XGetWindowAttributes(xdev->dpy, xdev->win, &attrib)) {
  237.         xdev->scr = attrib.screen;
  238.         xvinfo.visual = attrib.visual;
  239.         xdev->cmap = attrib.colormap;
  240.         xdev->width = attrib.width;
  241.         xdev->height = attrib.height;
  242.     }
  243.     /* Delete property if explicit dest is given */
  244.     if (XGetWindowProperty(xdev->dpy, xdev->win, ghostview_atom, 0,
  245.                    256, (xdev->dest != 0), XA_STRING,
  246.                    &type, &format, &nitems, &bytes_after,
  247.                    (unsigned char **)&buf) == 0 &&
  248.         type == XA_STRING) {
  249.         int llx, lly, urx, ury;
  250.         int left_margin = 0, bottom_margin = 0;
  251.         int right_margin = 0, top_margin = 0;
  252.  
  253.         /* We declare page_orientation as an int so that we can */
  254.         /* use an int * to reference it for sscanf; compilers */
  255.         /* might be tempted to use less space to hold it if */
  256.         /* it were declared as an orientation. */
  257.         int    /*orientation*/ page_orientation;
  258.         float xppp, yppp;    /* pixels per point */
  259.         nitems = sscanf(buf,
  260.                 "%ld %d %d %d %d %d %f %f %d %d %d %d",
  261.                 &(xdev->bpixmap), &page_orientation,
  262.                 &llx, &lly, &urx, &ury,
  263.                 &(xdev->x_pixels_per_inch),
  264.                 &(xdev->y_pixels_per_inch),
  265.                 &left_margin, &bottom_margin,
  266.                 &right_margin, &top_margin);
  267.         if (!(nitems == 8 || nitems == 12)) {
  268.         eprintf("Cannot get ghostview property.\n");
  269.         return_error(gs_error_ioerror);
  270.         }
  271.         if (xdev->dest && xdev->bpixmap) {
  272.         eprintf("Both destination and backing pixmap specified.\n");
  273.         return_error(gs_error_rangecheck);
  274.         }
  275.         if (xdev->dest) {
  276.         Window root;
  277.         int x, y;
  278.         unsigned int width, height;
  279.         unsigned int border_width, depth;
  280.  
  281.         if (XGetGeometry(xdev->dpy, xdev->dest, &root, &x, &y,
  282.                  &width, &height, &border_width, &depth)) {
  283.             xdev->width = width;
  284.             xdev->height = height;
  285.         }
  286.         }
  287.         xppp = xdev->x_pixels_per_inch / 72.0;
  288.         yppp = xdev->y_pixels_per_inch / 72.0;
  289.         switch (page_orientation) {
  290.         case Portrait:
  291.         xdev->initial_matrix.xx = xppp;
  292.         xdev->initial_matrix.xy = 0.0;
  293.         xdev->initial_matrix.yx = 0.0;
  294.         xdev->initial_matrix.yy = -yppp;
  295.         xdev->initial_matrix.tx = -llx * xppp;
  296.         xdev->initial_matrix.ty = ury * yppp;
  297.         break;
  298.         case Landscape:
  299.         xdev->initial_matrix.xx = 0.0;
  300.         xdev->initial_matrix.xy = yppp;
  301.         xdev->initial_matrix.yx = xppp;
  302.         xdev->initial_matrix.yy = 0.0;
  303.         xdev->initial_matrix.tx = -lly * xppp;
  304.         xdev->initial_matrix.ty = -llx * yppp;
  305.         break;
  306.         case Upsidedown:
  307.         xdev->initial_matrix.xx = -xppp;
  308.         xdev->initial_matrix.xy = 0.0;
  309.         xdev->initial_matrix.yx = 0.0;
  310.         xdev->initial_matrix.yy = yppp;
  311.         xdev->initial_matrix.tx = urx * xppp;
  312.         xdev->initial_matrix.ty = -lly * yppp;
  313.         break;
  314.         case Seascape:
  315.         xdev->initial_matrix.xx = 0.0;
  316.         xdev->initial_matrix.xy = -yppp;
  317.         xdev->initial_matrix.yx = -xppp;
  318.         xdev->initial_matrix.yy = 0.0;
  319.         xdev->initial_matrix.tx = ury * xppp;
  320.         xdev->initial_matrix.ty = urx * yppp;
  321.         break;
  322.         }
  323.  
  324.         /* The following sets the imageable area according to the */
  325.         /* bounding box and margins sent by ghostview.            */
  326.         /* This code has been patched many times; its current state */
  327.         /* is per a recommendation by Tim Theisen on 4/28/95. */
  328.  
  329.         xdev->ImagingBBox[0] = llx - left_margin;
  330.         xdev->ImagingBBox[1] = lly - bottom_margin;
  331.         xdev->ImagingBBox[2] = urx + right_margin;
  332.         xdev->ImagingBBox[3] = ury + top_margin;
  333.         xdev->ImagingBBox_set = true;
  334.  
  335.     } else if (xdev->pwin == (Window)None) {
  336.         eprintf("Cannot get ghostview property.\n");
  337.         return_error(gs_error_ioerror);
  338.     }
  339.     } else {
  340.     Screen *scr = DefaultScreenOfDisplay(xdev->dpy);
  341.  
  342.     xdev->scr = scr;
  343.     xvinfo.visual = DefaultVisualOfScreen(scr);
  344.     xdev->cmap = DefaultColormapOfScreen(scr);
  345.     }
  346.  
  347.     xvinfo.visualid = XVisualIDFromVisual(xvinfo.visual);
  348.     xdev->vinfo = XGetVisualInfo(xdev->dpy, VisualIDMask, &xvinfo, &nitems);
  349.     if (xdev->vinfo == NULL) {
  350.     eprintf("Cannot get XVisualInfo.\n");
  351.     return_error(gs_error_ioerror);
  352.     }
  353.  
  354.     /* Buggy X servers may cause a Bad Access on XFreeColors. */
  355.     orighandler = XSetErrorHandler(x_catch_free_colors);
  356.  
  357.     /* Get X Resources.  Use the toolkit for this. */
  358.     XtToolkitInitialize();
  359.     app_con = XtCreateApplicationContext();
  360.     XtAppSetFallbackResources(app_con, fallback_resources);
  361.     dpy = XtOpenDisplay(app_con, NULL, "ghostscript", "Ghostscript",
  362.             NULL, 0, &zero, NULL);
  363.     toplevel = XtAppCreateShell(NULL, "Ghostscript",
  364.                 applicationShellWidgetClass, dpy, NULL, 0);
  365.     XtGetApplicationResources(toplevel, (XtPointer) xdev,
  366.                   resources, XtNumber(resources), NULL, 0);
  367.  
  368.     /* Reserve foreground and background colors under the regular connection. */
  369.     xc.pixel = xdev->foreground;
  370.     XQueryColor(xdev->dpy, xdev->cmap, &xc);
  371.     XAllocColor(xdev->dpy, xdev->cmap, &xc);
  372.     xc.pixel = xdev->background;
  373.     XQueryColor(xdev->dpy, xdev->cmap, &xc);
  374.     XAllocColor(xdev->dpy, xdev->cmap, &xc);
  375.  
  376.     code = gdev_x_setup_colors(xdev);
  377.     if ( code < 0 )
  378.       { XCloseDisplay(xdev->dpy);
  379.         return code;
  380.       }
  381.     gdev_x_setup_fontmap(xdev);
  382.  
  383.     if (!xdev->ghostview) {
  384.     XWMHints wm_hints;
  385.     XSetWindowAttributes xswa;
  386.     gx_device *dev = (gx_device *)xdev;
  387.  
  388.     /* Take care of resolution and paper size. */
  389.     if (xdev->x_pixels_per_inch == FAKE_RES ||
  390.         xdev->y_pixels_per_inch == FAKE_RES) {
  391.         float xsize = (float)xdev->width / xdev->x_pixels_per_inch;
  392.         float ysize = (float)xdev->height / xdev->y_pixels_per_inch;
  393.  
  394.         if (xdev->xResolution == 0.0 && xdev->yResolution == 0.0) {
  395.         float dpi, xdpi, ydpi;
  396.  
  397.         xdpi = 25.4 * WidthOfScreen(xdev->scr) /
  398.                WidthMMOfScreen(xdev->scr);
  399.         ydpi = 25.4 * HeightOfScreen(xdev->scr) /
  400.                HeightMMOfScreen(xdev->scr);
  401.         dpi = min(xdpi, ydpi);
  402.         /*
  403.          * Some X servers provide very large "virtual screens", and
  404.          * return the virtual screen size for Width/HeightMM but the
  405.          * physical size for Width/Height.  Attempt to detect and
  406.          * correct for this now.  This is a KLUDGE required because
  407.          * the X server provides no way to read the screen
  408.          * resolution directly.
  409.          */
  410.         if ( dpi < 30 )
  411.           dpi = 75;        /* arbitrary */
  412.         else
  413.           { while (xsize*dpi > WidthOfScreen(xdev->scr)-32 ||
  414.                ysize*dpi > HeightOfScreen(xdev->scr)-32)
  415.               dpi *= 0.95;
  416.           }
  417.         xdev->x_pixels_per_inch = dpi;
  418.         xdev->y_pixels_per_inch = dpi;
  419.         } else {
  420.         xdev->x_pixels_per_inch = xdev->xResolution;
  421.         xdev->y_pixels_per_inch = xdev->yResolution;
  422.         }
  423.         if (xdev->width > WidthOfScreen(xdev->scr)) {
  424.         xdev->width = xsize*xdev->x_pixels_per_inch;
  425.         }
  426.         if (xdev->height > HeightOfScreen(xdev->scr)) {
  427.         xdev->height = ysize*xdev->y_pixels_per_inch;
  428.         }
  429.         xdev->MediaSize[0] =
  430.           (float)xdev->width / xdev->x_pixels_per_inch * 72;
  431.         xdev->MediaSize[1] =
  432.           (float)xdev->height / xdev->y_pixels_per_inch * 72;
  433.     }
  434.  
  435.     sizehints.x = 0;
  436.     sizehints.y = 0;
  437.     sizehints.width = xdev->width;
  438.     sizehints.height = xdev->height;
  439.     sizehints.flags = 0;
  440.  
  441.     if (xdev->geometry != NULL) {
  442.         /*
  443.          * Note that border_width must be set first.  We can't use
  444.          * scr, because that is a Screen*, and XWMGeometry wants
  445.          * the screen number.
  446.          */
  447.         char gstr[40];
  448.         int bitmask;
  449.  
  450.         sprintf(gstr, "%dx%d+%d+%d", sizehints.width,
  451.             sizehints.height, sizehints.x, sizehints.y);
  452.         bitmask = XWMGeometry(xdev->dpy, DefaultScreen(xdev->dpy),
  453.                   xdev->geometry, gstr, xdev->borderWidth,
  454.                   &sizehints,
  455.                   &sizehints.x, &sizehints.y,
  456.                   &sizehints.width, &sizehints.height,
  457.                   &sizehints.win_gravity);
  458.  
  459.         if (bitmask & (XValue | YValue))
  460.         sizehints.flags |= USPosition;
  461.     }
  462.  
  463.     gx_default_get_initial_matrix(dev, &(xdev->initial_matrix));
  464.     
  465.     if (xdev->pwin != (Window)None && xid_width != 0 && xid_height != 0) {
  466. #if 0    /****************/
  467.  
  468.         /*
  469.          * The user who originally implemented the WindowID feature
  470.          * provided the following code to scale the displayed output
  471.          * to fit in the window.  We think this is a bad idea,
  472.          * since it doesn't track window resizing and is generally
  473.          * completely at odds with the way Ghostscript treats
  474.          * window or paper size in all other contexts.  We are
  475.          * leaving the code here in case someone decides that
  476.          * this really is the behavior they want.
  477.          */
  478.  
  479.         /* Scale to fit in the window. */
  480.         xdev->initial_matrix.xx 
  481.         = xdev->initial_matrix.xx * 
  482.         (float)xid_width / (float)xdev->width;
  483.         xdev->initial_matrix.yy 
  484.         = xdev->initial_matrix.yy *
  485.         (float)xid_height / (float)xdev->height;
  486.  
  487. #endif    /****************/
  488.         xdev->width = xid_width;
  489.         xdev->height = xid_height;
  490.         xdev->initial_matrix.ty = xdev->height;
  491.     } else {        /* !xdev->pwin */
  492.         xswa.event_mask = ExposureMask;
  493.         xswa.background_pixel = xdev->background;
  494.         xswa.border_pixel = xdev->borderColor;
  495.         xswa.colormap = xdev->cmap;
  496.         xdev->win = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
  497.                       sizehints.x, sizehints.y,    /* upper left */
  498.                       xdev->width, xdev->height,
  499.                       xdev->borderWidth,
  500.                       xdev->vinfo->depth,
  501.                       InputOutput,    /* class     */
  502.                       xdev->vinfo->visual,    /* visual */
  503.                       CWEventMask | CWBackPixel |
  504.                       CWBorderPixel | CWColormap,
  505.                       &xswa);
  506.         XStoreName(xdev->dpy, xdev->win, "ghostscript");
  507.         XSetWMNormalHints(xdev->dpy, xdev->win, &sizehints);
  508.         wm_hints.flags = InputHint;
  509.         wm_hints.input = False;
  510.         XSetWMHints(xdev->dpy, xdev->win, &wm_hints); /* avoid input focus */
  511.     }
  512.     }
  513.  
  514.     /***
  515.      *** According to Ricard Torres (torres@upf.es), we have to wait until here
  516.      *** to close the toolkit connection, which we formerly did
  517.      *** just after the calls on XAllocColor above.  I suspect that
  518.      *** this will cause things to be left dangling if an error occurs
  519.      *** anywhere in the above code, but I'm willing to let users
  520.      *** fight over fixing it, since I have no idea what's right.
  521.      ***/
  522.  
  523.     /* And close the toolkit connection. */
  524.     XtDestroyWidget(toplevel);
  525.     XtCloseDisplay(dpy);
  526.     XtDestroyApplicationContext(app_con);
  527.  
  528.     xdev->ht.pixmap = (Pixmap) 0;
  529.     xdev->ht.id = gx_no_bitmap_id;;
  530.     xdev->fill_style = FillSolid;
  531.     xdev->function = GXcopy;
  532.     xdev->fid = (Font) 0;
  533.  
  534.     /* Set up a graphics context */
  535.     xdev->gc = XCreateGC(xdev->dpy, xdev->win, 0, (XGCValues *) NULL);
  536.     XSetFunction(xdev->dpy, xdev->gc, GXcopy);
  537.     XSetLineAttributes(xdev->dpy, xdev->gc, 0,
  538.                LineSolid, CapButt, JoinMiter);
  539.  
  540.     gdev_x_clear_window(xdev);
  541.  
  542.     if (!xdev->ghostview) {    /* Make the window appear. */
  543.     XMapWindow(xdev->dpy, xdev->win);
  544.  
  545.     /* Before anything else, do a flush and wait for */
  546.     /* an exposure event. */
  547.     XFlush(xdev->dpy);
  548.     if (xdev->pwin == (Window)None) {    /* there isn't a next event for existing windows */
  549.         XNextEvent(xdev->dpy, &event);
  550.     }
  551.     /* Now turn off graphics exposure events so they don't queue up */
  552.     /* indefinitely.  Also, since we can't do anything about real */
  553.     /* Expose events, mask them out. */
  554.     XSetGraphicsExposures(xdev->dpy, xdev->gc, False);
  555.     XSelectInput(xdev->dpy, xdev->win, NoEventMask);
  556.     } else {
  557.     /* Create an unmapped window, that the window manager will ignore.
  558.      * This invisible window will be used to receive "next page"
  559.      * events from ghostview */
  560.     XSetWindowAttributes attributes;
  561.  
  562.     attributes.override_redirect = True;
  563.     xdev->mwin = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
  564.                    0, 0, 1, 1, 0, CopyFromParent,
  565.                    CopyFromParent, CopyFromParent,
  566.                    CWOverrideRedirect, &attributes);
  567.     xdev->NEXT = XInternAtom(xdev->dpy, "NEXT", False);
  568.     xdev->PAGE = XInternAtom(xdev->dpy, "PAGE", False);
  569.     xdev->DONE = XInternAtom(xdev->dpy, "DONE", False);
  570.     }
  571.  
  572.     xdev->ht.no_pixmap = XCreatePixmap(xdev->dpy, xdev->win, 1, 1,
  573.                        xdev->vinfo->depth);
  574.  
  575.     return 0;
  576. }
  577.  
  578. /* Allocate the backing pixmap, if any, and clear the window. */
  579. void
  580. gdev_x_clear_window(gx_device_X *xdev)
  581. {
  582.     if (!xdev->ghostview) {
  583.     if (xdev->useBackingPixmap) {
  584.         oldhandler = XSetErrorHandler(x_catch_alloc);
  585.         alloc_error = False;
  586.         xdev->bpixmap =
  587.         XCreatePixmap(xdev->dpy, xdev->win,
  588.                   xdev->width, xdev->height,
  589.                   xdev->vinfo->depth);
  590.         XSync(xdev->dpy, False);    /* Force the error */
  591.         if (alloc_error) {
  592.         xdev->useBackingPixmap = False;
  593. #ifdef DEBUG
  594.         eprintf("Warning: Failed to allocated backing pixmap.\n");
  595. #endif
  596.         if (xdev->bpixmap) {
  597.             XFreePixmap(xdev->dpy, xdev->bpixmap);
  598.             xdev->bpixmap = None;
  599.             XSync(xdev->dpy, False);    /* Force the error */
  600.         }
  601.         }
  602.         oldhandler = XSetErrorHandler(oldhandler);
  603.     } else
  604.         xdev->bpixmap = (Pixmap) 0;
  605.     }
  606.     /* Clear the destination pixmap to avoid initializing with garbage. */
  607.     if (xdev->dest != (Pixmap) 0) {
  608.     XSetForeground(xdev->dpy, xdev->gc, xdev->background);
  609.     XFillRectangle(xdev->dpy, xdev->dest, xdev->gc,
  610.                0, 0, xdev->width, xdev->height);
  611.     } else {
  612.     xdev->dest = (xdev->bpixmap != (Pixmap) 0 ?
  613.               xdev->bpixmap : (Pixmap) xdev->win);
  614.     }
  615.  
  616.     /* Clear the background pixmap to avoid initializing with garbage. */
  617.     if (xdev->bpixmap != (Pixmap) 0) {
  618.     if (!xdev->ghostview)
  619.         XSetWindowBackgroundPixmap(xdev->dpy, xdev->win, xdev->bpixmap);
  620.     XSetForeground(xdev->dpy, xdev->gc, xdev->background);
  621.     XFillRectangle(xdev->dpy, xdev->bpixmap, xdev->gc,
  622.                0, 0, xdev->width, xdev->height);
  623.     }
  624.     /* Initialize foreground and background colors */
  625.     xdev->back_color = xdev->background;
  626.     XSetBackground(xdev->dpy, xdev->gc, xdev->background);
  627.     xdev->fore_color = xdev->background;
  628.     XSetForeground(xdev->dpy, xdev->gc, xdev->background);
  629.     xdev->colors_or = xdev->colors_and = xdev->background;
  630. }
  631.  
  632. /* ------ Initialize color mapping ------ */
  633.  
  634. #if HaveStdCMap
  635. /* Get the Standard colormap if available. */
  636. private XStandardColormap *
  637. x_get_std_cmap(gx_device_X *xdev, Atom prop)
  638. {
  639.     int i;
  640.     XStandardColormap *scmap, *sp;
  641.     int nitems;
  642.  
  643.     if (XGetRGBColormaps(xdev->dpy, RootWindowOfScreen(xdev->scr),
  644.              &scmap, &nitems, prop))
  645.     for (i = 0, sp = scmap; i < nitems; i++, sp++)
  646.         if (xdev->cmap == sp->colormap)
  647.         return sp;
  648.  
  649.     return NULL;
  650. }
  651. #endif
  652.  
  653. /* Allocate the dynamic color table, if needed and possible. */
  654. private void
  655. alloc_dynamic_colors(gx_device_X *xdev, int reserved_colors)
  656. {
  657.     /* Allocate space for dynamic colors hash table */
  658.     xdev->dynamic_colors =
  659.           (x11color*(*)[]) gs_malloc(sizeof(x11color *), xdev->num_rgb,
  660.                      "x11_dynamic_colors");
  661.  
  662.     if (xdev->dynamic_colors) {
  663.         int i;
  664.         xdev->dynamic_size = xdev->num_rgb;
  665.         for (i = 0; i < xdev->num_rgb; i++) {
  666.         (*xdev->dynamic_colors)[i] = NULL;
  667.         }
  668.         xdev->max_dynamic_colors = min(256, xdev->vinfo->colormap_size -
  669.                             reserved_colors);
  670.     }
  671. }
  672.  
  673. /* Free a partially filled color ramp. */
  674. private void
  675. free_ramp(gx_device_X *xdev, int num_used, int size)
  676. {    if ( num_used - 1 > 0 )
  677.       {    XFreeColors(xdev->dpy, xdev->cmap,
  678.                 xdev->dither_colors + 1,
  679.                 num_used - 1, 0);
  680.       }
  681.     gs_free((char *)xdev->dither_colors, sizeof(x_pixel), size,
  682.         "x11_setup_colors");
  683.     xdev->dither_colors = NULL;
  684. }
  685.  
  686. /* Allocate and fill in a color cube or ramp. */
  687. /* Return true if the operation succeeded. */
  688. private bool
  689. setup_cube(gx_device_X *xdev, int ramp_size, bool colors)
  690. {    int step, num_entries;
  691.     int max_rgb = ramp_size - 1;
  692.     int index;
  693.  
  694.     if ( colors )
  695.       {    num_entries = ramp_size * ramp_size * ramp_size;
  696.         step = 1;    /* all colors */
  697.       }
  698.     else
  699.       {    num_entries = ramp_size;
  700.         step = (ramp_size + 1) * ramp_size + 1;    /* gray only */
  701.       }
  702.  
  703.     xdev->dither_colors =
  704.       (x_pixel *)gs_malloc(sizeof(x_pixel), num_entries,
  705.                    "gdevx setup_cube");
  706.     if ( xdev->dither_colors == NULL )
  707.       return false;
  708.  
  709.     xdev->dither_colors[0] = xdev->foreground;
  710.     xdev->dither_colors[num_entries - 1] = xdev->background;
  711.     for ( index = 1; index < num_entries - 1; index++ )
  712.       {    int rgb_index = index * step;
  713.         int r = rgb_index / (ramp_size * ramp_size);
  714.         int g = (rgb_index / ramp_size) % ramp_size;
  715.         int b = rgb_index % ramp_size;
  716.         XColor xc;
  717.  
  718.         xc.red = (X_max_color_value * r / max_rgb) & xdev->color_mask;
  719.         xc.green = (X_max_color_value * g / max_rgb) & xdev->color_mask;
  720.         xc.blue = (X_max_color_value * b / max_rgb) & xdev->color_mask;
  721.         if ( XAllocColor(xdev->dpy, xdev->cmap, &xc) )
  722.           {    xdev->dither_colors[index] = xc.pixel;
  723.           }
  724.         else
  725.           {    free_ramp(xdev, index, num_entries);
  726.             return false;
  727.           }
  728.       }
  729.  
  730.     return true;
  731. }
  732.  
  733. /* Setup color mapping. */
  734. private int
  735. gdev_x_setup_colors(gx_device_X *xdev)
  736. {
  737.     char palette;
  738.  
  739.     palette = ((xdev->vinfo->class != StaticGray) &&
  740.            (xdev->vinfo->class != GrayScale) ? 'C' :  /* Color */
  741.            (xdev->vinfo->colormap_size > 2) ?  'G' :  /* GrayScale */
  742.                            'M');  /* MonoChrome */
  743.     if (xdev->ghostview) {
  744.     Atom gv_colors = XInternAtom(xdev->dpy, "GHOSTVIEW_COLORS", False);
  745.     Atom type;
  746.     int format;
  747.     unsigned long nitems, bytes_after;
  748.     char *buf;
  749.  
  750.     /* Delete property if explicit dest is given */
  751.     if (XGetWindowProperty(xdev->dpy, xdev->win, gv_colors, 0,
  752.                    256, (xdev->dest != 0), XA_STRING,
  753.                    &type, &format, &nitems, &bytes_after,
  754.                    (unsigned char **)&buf) == 0 &&
  755.         type == XA_STRING) {
  756.         nitems = sscanf(buf, "%*s %ld %ld", &(xdev->foreground),
  757.                                 &(xdev->background));
  758.         if (nitems != 2 || (*buf != 'M' && *buf != 'G' && *buf != 'C')) {
  759.         eprintf("Malformed ghostview color property.\n");
  760.         return_error(gs_error_rangecheck);
  761.         }
  762.         palette = max(palette, *buf);
  763.     }
  764.     } else {
  765.     if    (xdev->palette[0] == 'c') xdev->palette[0] = 'C';
  766.     else if (xdev->palette[0] == 'g') xdev->palette[0] = 'G';
  767.     else if (xdev->palette[0] == 'm') xdev->palette[0] = 'M';
  768.     palette = max(palette, xdev->palette[0]);
  769.     }
  770.  
  771.     /* set up color mappings here */
  772.     xdev->color_mask = X_max_color_value -
  773.                (X_max_color_value >> xdev->vinfo->bits_per_rgb);
  774.     xdev->num_rgb = 1 << xdev->vinfo->bits_per_rgb;
  775.  
  776. #if HaveStdCMap
  777.     xdev->std_cmap = NULL;
  778. #endif
  779.     xdev->dither_colors = NULL;
  780.     xdev->dynamic_colors = NULL;
  781.     xdev->dynamic_size = 0;
  782.     xdev->dynamic_allocs = 0;
  783.     xdev->color_info.depth = xdev->vinfo->depth;
  784.  
  785.     if (palette == 'C') {
  786.     xdev->color_info.num_components = 3;
  787.     xdev->color_info.max_gray =
  788.         xdev->color_info.max_color = xdev->num_rgb - 1;
  789. #if HaveStdCMap
  790.     /* Get a standard color map if available */
  791.     if (xdev->vinfo->visual == DefaultVisualOfScreen(xdev->scr)) {
  792.         xdev->std_cmap = x_get_std_cmap(xdev, XA_RGB_DEFAULT_MAP);
  793.     } else {
  794.         xdev->std_cmap = x_get_std_cmap(xdev, XA_RGB_BEST_MAP);
  795.     }
  796.     if (xdev->std_cmap) {
  797.         xdev->color_info.dither_grays =
  798.         xdev->color_info.dither_colors =
  799.         min(xdev->std_cmap->red_max,
  800.             min(xdev->std_cmap->green_max,
  801.             xdev->std_cmap->blue_max)) + 1;
  802.     } else
  803. #endif
  804.     /* Otherwise set up a rgb cube of our own */
  805.     /* The color cube is limited to about 1/2 of the available */
  806.     /* colormap, the user specified maxRGBRamp (usually 5), */
  807.     /* or the number of representable colors */
  808. #define cube(r) (r*r*r)
  809. #define cbrt(r) pow(r, 1.0/3.0)
  810.     {
  811.         int ramp_size =
  812.             min((int)cbrt((double)xdev->vinfo->colormap_size / 2.0),
  813.                 min(xdev->maxRGBRamp, xdev->num_rgb));
  814.  
  815.         while (!xdev->dither_colors && ramp_size >= 2) {
  816.         xdev->color_info.dither_grays =
  817.             xdev->color_info.dither_colors = ramp_size;
  818.         if ( !setup_cube(xdev, ramp_size, true) ) {
  819. #ifdef DEBUG
  820.           eprintf3("Warning: failed to allocate %dx%dx%d RGB cube.\n",
  821.                ramp_size, ramp_size, ramp_size);
  822. #endif
  823.           ramp_size--;
  824.           continue;
  825.         }
  826.         }
  827.  
  828.         if (!xdev->dither_colors) {
  829.         goto grayscale;
  830.         }
  831.     }
  832.  
  833.     /* Allocate the dynamic color table. */
  834.     alloc_dynamic_colors(xdev, cube(xdev->color_info.dither_colors));
  835.  
  836. #undef cube
  837. #undef cbrt
  838.     } else if (palette == 'G') {
  839. grayscale:
  840.     xdev->color_info.num_components = 1;
  841.     xdev->color_info.max_gray = xdev->num_rgb - 1;
  842. #if HaveStdCMap
  843.     /* Get a standard color map if available */
  844.         xdev->std_cmap = x_get_std_cmap(xdev, XA_RGB_GRAY_MAP);
  845.     if (xdev->std_cmap != 0) {
  846.         xdev->color_info.dither_grays = xdev->std_cmap->red_max +
  847.         xdev->std_cmap->green_max +
  848.         xdev->std_cmap->blue_max + 1;
  849.     } else
  850. #endif
  851.     /* Otherwise set up a gray ramp of our own */
  852.     /* The gray ramp is limited to about 1/2 of the available */
  853.     /* colormap, the user specified maxGrayRamp (usually 128), */
  854.     /* or the number of representable grays */
  855.     {
  856.         int ramp_size = min(xdev->vinfo->colormap_size / 2,
  857.                 min(xdev->maxGrayRamp, xdev->num_rgb));
  858.  
  859.         while (!xdev->dither_colors && ramp_size >= 3) {
  860.         xdev->color_info.dither_grays = ramp_size;
  861.         if ( !setup_cube(xdev, ramp_size, false) )
  862.         {
  863. #ifdef DEBUG
  864.           eprintf1("Warning: failed to allocate %d level gray ramp.\n",
  865.                ramp_size);
  866. #endif
  867.           ramp_size /= 2;
  868.           continue;
  869.         }
  870.         }
  871.         if (!xdev->dither_colors) {
  872.         goto monochrome;
  873.         }
  874.     }
  875.  
  876.     /* Allocate the dynamic color table. */
  877.     alloc_dynamic_colors(xdev, xdev->color_info.dither_grays);
  878.  
  879.     } else if (palette == 'M') {
  880. monochrome:
  881.     xdev->color_info.num_components = 1;
  882.     xdev->color_info.max_gray = 1;
  883.     xdev->color_info.dither_grays = 2;
  884.     } else {
  885.     eprintf1("Unknown palette: %s\n", xdev->palette);
  886.     return_error(gs_error_rangecheck);
  887.     }
  888.     return 0;
  889. }
  890.  
  891. /* ------ Initialize font mapping ------ */
  892.  
  893. /* Extract the PostScript font name from the font map resource. */
  894. private const char *
  895. get_ps_name(const char **cpp, int *len)
  896. {
  897.     const char *ret;
  898.     *len = 0;
  899.     /* skip over whitespace and newlines */
  900.     while (**cpp == ' ' || **cpp == '\t' || **cpp == '\n') {
  901.     (*cpp)++;
  902.     }
  903.     /* return font name up to ":", whitespace, or end of string */
  904.     if (**cpp == ':' || **cpp == '\0') {
  905.     return NULL;
  906.     }
  907.     ret = *cpp;
  908.     while (**cpp != ':' &&
  909.        **cpp != ' ' && **cpp != '\t' && **cpp != '\n' &&
  910.        **cpp != '\0') {
  911.     (*cpp)++;
  912.     (*len)++;
  913.     }
  914.     return ret;
  915. }
  916.  
  917. /* Extract the X11 font name from the font map resource. */
  918. private const char *
  919. get_x11_name(const char **cpp, int *len)
  920. {
  921.     const char *ret;
  922.     int dashes = 0;
  923.     *len = 0;
  924.     /* skip over whitespace and the colon */
  925.     while (**cpp == ' ' || **cpp == '\t' ||
  926.        **cpp == ':') {
  927.     (*cpp)++;
  928.     }
  929.     /* return font name up to end of line or string */
  930.     if (**cpp == '\0' || **cpp == '\n') {
  931.     return NULL;
  932.     }
  933.     ret = *cpp;
  934.     while (dashes != 7 &&
  935.        **cpp != '\0' && **cpp != '\n') {
  936.     if (**cpp == '-') dashes++;
  937.     (*cpp)++;
  938.     (*len)++;
  939.     }
  940.     while (**cpp != '\0' && **cpp != '\n') {
  941.     (*cpp)++;
  942.     }
  943.     if (dashes != 7) return NULL;
  944.     return ret;
  945. }
  946.  
  947. /* Scan one resource and build font map records. */
  948. private void
  949. scan_font_resource(const char *resource, x11fontmap **pmaps)
  950. {
  951.     const char *ps_name;
  952.     const char *x11_name;
  953.     int ps_name_len;
  954.     int x11_name_len;
  955.     x11fontmap *font;
  956.     const char *cp = resource;
  957.  
  958.     while ((ps_name = get_ps_name(&cp, &ps_name_len)) != 0) {
  959.     x11_name = get_x11_name(&cp, &x11_name_len);
  960.     if (x11_name) {
  961.         font = (x11fontmap *)gs_malloc(sizeof(x11fontmap), 1,
  962.                        "x11_setup_fontmap");
  963.         if (font == NULL) continue;
  964.         font->ps_name = (char *)gs_malloc(sizeof(char), ps_name_len+1,
  965.                           "x11_setup_fontmap");
  966.         if (font->ps_name == NULL) {
  967.         gs_free((char *)font, sizeof(x11fontmap), 1, "x11_fontmap");
  968.         continue;
  969.         }
  970.         strncpy(font->ps_name, ps_name, ps_name_len);
  971.         font->ps_name[ps_name_len] = '\0';
  972.         font->x11_name = (char *)gs_malloc(sizeof(char), x11_name_len,
  973.                            "x11_setup_fontmap");
  974.         if (font->x11_name == NULL) {
  975.         gs_free(font->ps_name, sizeof(char), strlen(font->ps_name)+1,
  976.             "x11_font_psname");
  977.         gs_free((char *)font, sizeof(x11fontmap), 1, "x11_fontmap");
  978.         continue;
  979.         }
  980.         strncpy(font->x11_name, x11_name, x11_name_len-1);
  981.         font->x11_name[x11_name_len-1] = '\0';
  982.         font->std_names = NULL;
  983.         font->iso_names = NULL;
  984.         font->std_count = -1;
  985.         font->iso_count = -1;
  986.         font->next = *pmaps;
  987.         *pmaps = font;
  988.     }
  989.     }
  990. }
  991.  
  992. /* Scan all the font resources and set up the maps. */
  993. private void
  994. gdev_x_setup_fontmap(gx_device_X *xdev)
  995. {
  996.     if (!xdev->useXFonts) return;    /* If no external fonts, don't bother */
  997.  
  998.     scan_font_resource(xdev->regularFonts, &xdev->regular_fonts);
  999.     scan_font_resource(xdev->symbolFonts, &xdev->symbol_fonts);
  1000.     scan_font_resource(xdev->dingbatFonts, &xdev->dingbat_fonts);
  1001. }
  1002.